package compiler;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

import lexer.*;
import parser.*;
import tree.*;
import code.*;

/**
 * Main class for the SO-Compiler, reads a source-code File and compiles the program
 * and writes the target-code to an File, specifies by the argument -o data.sovm 
 * @author sebastian
 */
public class CompilerMain {

	/**
	 * Main-Method
	 * @param args CommandLine Arguments, e.g inputFile and outputFile
	 * @throws ParserException, when program is syntactic wrong
	 * @throws CompilerException, when there is no inputFile
	 * @throws NamingException, while name-analysis
	 * @throws TypingException, while typ-analysis
	 */
	public static void main(String[] args) throws ParserException, CompilerException,
		NamingException, TypingException {
		boolean debug = true;
		String file = "";
		String output = "";
		String targetCode = "";
		String programCode = "";
		Lexer lex;
		Parser parser;
		Tree myTree;
		TargetCode code = new TargetCode();
		IdentifierScope identScope = new IdentifierScope(null);
		MethodScope methodScope = new MethodScope(null);
		ClassScope classScope = new ClassScope(null);
		if (args.length==0) {
			throw new CompilerException("No input files");
		}
		if (args.length > 1) {
			if (args[1].equals("-o")) {
				if (args.length >= 3) {
					output = args[2];
				}
				else {
					throw new CompilerException("No outputFile specifed");
				}
			}
			else {
				System.err.println("Your options are ignored at the moment");
			}
			file = args[0];
		}
		else {
			throw new CompilerException("No output specified");
		}
		try {
			programCode = readFile(file, "Quell-Datei");
			lex = new Lexer(programCode);
			parser = new Parser(new MyTreeFactory(), lex);
			myTree = parser.parse(false);
			System.out.println(myTree.toString());
			myTree.preAnalyzeNames(identScope, methodScope, classScope);
			myTree.analyzeNames(identScope, methodScope, classScope);
			System.out.println("IdentifierScope:\n"+identScope.toString());
			System.out.println("MethodScope:\n"+methodScope.toString());
			System.out.println("ClassScope:\n"+classScope.toString());
			myTree.computeType();
			myTree.generateProgramCode(code);
			targetCode = code.toSOVMLanguage();
			writeOutput(output, targetCode.toString()+"\n");
		}
		catch (Exception e) {
			System.out.println(e.getMessage());
			if (debug) {
				e.printStackTrace();
				System.out.println();
			}
		}
	}
	
	/**
	 * Reads the source-code File to a String
	 * @param codeFile , where the sourceCodeFile is located
	 * @return the string representation of the source-code
	 */
	public static String readFile(String codeFile, String dat) {
		String ruckgabe = "";
		File filename = new File (codeFile);
		boolean doesexist = filename.exists();
		if (doesexist) {
			boolean readable = filename.canRead();
			if (readable) {
				try {
					FileReader reader = new FileReader(filename);
					BufferedReader input = new BufferedReader(reader);
					while (input.ready()) {
						ruckgabe = ruckgabe + input.readLine() + "\n";
					}
					input.close();
					reader.close();
				}
				catch (IOException e) {
					System.err.println("Internal Error, please report saarinformatix [at]" +
							"googlemail [dot] com");
					e.printStackTrace();
					System.exit(-1);
				}
			}
			else {
				System.err.println(dat + " kann nicht gelesen werden");
				System.exit(-1);
			}
		}
		else {
			System.err.println(dat + " existiert nicht!");
			System.exit(-1);
		}
		return ruckgabe;
	}

	private static void writeOutput(String targetCodeFile, String targetCode) 
			throws CompilerException {
		File filename = new File(targetCodeFile);
		if (filename.exists()) {
			throw new CompilerException("Output File exists already");
		}
		try {
			FileWriter writer = new FileWriter(filename,true);
			BufferedWriter output = new BufferedWriter(writer);
			output.write(targetCode);
			output.close();
			writer.close();
		}
		catch (IOException e) {
			System.err.println("Internal Error, please report saarinformatix [at]" +
			"googlemail [dot] com");
			e.printStackTrace();
			System.exit(-1);
		}
	}
	
}
